package com.batchengine.util;

import static com.batchengine.BatchEngine.getEngine;
import static com.batchengine.Definitions.OperationType.RESTART_POOL;
import static com.batchengine.Definitions.OperationType.STOP_POOL;
import com.batchengine.manager.ScheduledWorkerManager;
import com.batchengine.manager.SystemWorkerManager;
import com.batchengine.manager.WorkerManager;
import com.batchengine.pool.ProducerConsumerWorkerPool;
import com.batchengine.pool.WorkerPool;
import com.batchengine.schedular.CronSchedularWorkerManager;
import com.batchengine.system.SystemJobs;
import static com.batchengine.system.SystemJobs.getSystemJobFeeder;
import static com.batchengine.velocity.VelocityEngine.getHtmlTable;
import com.batchengine.worker.DataGatherer;
import com.batchengine.worker.ScheduledTask;
import com.batchengine.worker.Status;
import static com.batchengine.worker.Status.CANCELED;
import static com.batchengine.worker.Status.SCHEDULED;
import com.batchengine.worker.Worker;

import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import java.io.PrintWriter;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created by sunil.incubator@yahoo.com.
 * User: sunil.kalva
 * Date: Jul 11, 2009
 */

public class ControlPortHelper {

    public static void render(Object[][] data, String[] columnNames, PrintWriter writer, String tableHeader, boolean html) {

        if (html) {
            renderHTMLTable(data, columnNames, writer, tableHeader);
        } else {
            renderTable(data, columnNames, writer, tableHeader);
        }
    }

    public static void renderTable(Object[][] data, String[] columnNames, PrintWriter writer, String tableHeader) {

        TableModel tableModel = new DefaultTableModel(data, columnNames);
        TextTableRenderer renderer = new TextTableRenderer(tableModel);

        writer.println("");
        writer.println(String.format("#####################%s #####################", tableHeader));
        writer.println("");

        for (; renderer.hasNext();) {
            writer.println(renderer.getNextLine());
        }

        writer.println("");
        writer.println(String.format("#####################%s #####################", tableHeader));
        writer.println("");
    }

    public static void renderHTMLTable(Object[][] data, String[] columnNames, PrintWriter writer, String tableHeader) {

//        int rows = data.length;
//
//        writer.println("</br>");
//        writer.println(String.format("#####################%s #####################</br>", tableHeader));
//        writer.println("</br>");
//
//        writer.print("<table border=\"1\" cellpadding=\"1\" cellspacing=\"1\">");
//        writer.print("<tr>");
//        for (String columnName : columnNames) {
//            writer.print(String.format("<td>%s</td>", columnName));
//        }
//        writer.print("</tr>");
//        for (int i = 0; i < rows; i++) {
//
//            writer.print("<tr>");
//            for (int j = 0; j < columnNames.length; j++) {
//                writer.print(String.format("<td>%s</td>", data[i][j]));
//            }
//            writer.print("</tr>");
//        }
//        writer.print("</table>");
//
//        writer.println("</br>");
//        writer.println(String.format("#####################%s #####################</br>", tableHeader));
//        writer.println("</br>");

        writer.print(getHtmlTable(tableHeader, data, columnNames));
    }

    public static boolean displayUserManagers(PrintWriter writer, boolean html) {


        String[] columnNames = {"Id", "Manager Name", "Created Time", "No# Pools", "Total No# Workers"};

        Map<Integer, WorkerManager> tasks = getEngine().getManagers();
        Object[][] data = new Object[tasks.entrySet().size()][columnNames.length];

        Set<Integer> integers = tasks.keySet();
        int counter = 0;
        for (Integer integer : integers) {

            WorkerManager taskManger = tasks.get(integer);
            String link = MessageFormat.format("<a href=\"/bash/DisplayManager?managerId={0}\">{1}</a>", integer, taskManger.getName());
            data[counter][0] = integer;
            data[counter][1] = link;
            data[counter][2] = getSimpleDateString(taskManger.getStartTime());
            data[counter][3] = taskManger.getNumberOfActivePools().size();
            data[counter][4] = taskManger.getNumberOfActiveWorkers();
            counter++;
        }

        if (html) {
            renderHTMLTable(data, columnNames, writer, "Bash Engine Managers");
        }

        return true;
    }

    public static boolean displayManager(PrintWriter writer, String managerId, boolean html) {

        Map<Integer, WorkerManager> managers = getEngine().getManagers();
        WorkerManager taskManger = null;
        boolean error = false;
        try {
            taskManger = managers.get(Integer.parseInt(managerId));
        } catch (Exception e) {
            error = true;
        }
        if (taskManger instanceof ScheduledWorkerManager) {
            return displayScheduledManager(writer, managerId, taskManger, html);
        }

        String[] columnNames = {"Id", "Pool Name", "Min Workers", "Max Workers", "No# Workers", "Action"};

        if (null == taskManger || error) {
            writer.print("Task Id not found " + managerId);
            return false;
        }
        Object[][] data = new Object[taskManger.getNumberOfActivePools().size()][columnNames.length];
        Vector<WorkerPool> threadPools = taskManger.getNumberOfActivePools();
        int counter = 0;
        for (WorkerPool workflowThreadPool : threadPools) {

            String action = "N/A";
            if (workflowThreadPool.isBusy() || workflowThreadPool.isAlive()) {
                action = MessageFormat.format("<a href=\"/bash/killPool?managerId={0}&poolId={1}\">Stop Now</a>", managerId, workflowThreadPool.getPoolId());
            } else {
                action = MessageFormat.format("<a href=\"/bash/restartPool?managerId={0}&poolId={1}\">Start Now</a>", managerId, workflowThreadPool.getPoolId());
            }

            if (taskManger instanceof SystemWorkerManager) {
                action = "N/A";
            }

            data[counter][0] = workflowThreadPool.getPoolId();
            String poolLink = MessageFormat.format("<a href=\"/bash/displayPool?managerId={0}&poolId={1}\">{2}</a>", managerId, workflowThreadPool.getPoolId(), workflowThreadPool.getName());
            data[counter][1] = poolLink;
            data[counter][2] = workflowThreadPool.getMinWorkers();
            data[counter][3] = workflowThreadPool.getMaxWorkers();
            data[counter][4] = workflowThreadPool.getNumberOfWorkers();
            data[counter][5] = action;
            counter++;
        }
        render(data, columnNames, writer, managerId.toUpperCase(), html);

        return false;
    }

    public static boolean displayScheduledManager(PrintWriter writer, String managerId, WorkerManager taskManger, boolean html) {

        String[] columnNames = {"Id", "Task Id", "Scheduled Time", "Status", "Action"};

        ScheduledWorkerManager schManager = (ScheduledWorkerManager) taskManger;
        Map<Long, ScheduledTask> allScheduledTasks = schManager.getAllScheduledTasks();
        Object[][] data = new Object[allScheduledTasks.size()][columnNames.length];
        int counter = 0;
        Set<Long> taskSet = allScheduledTasks.keySet();
        for (Long taskId : taskSet) {

            ScheduledTask scheduledTask = allScheduledTasks.get(taskId);
            String action = "N/A";
            if (CANCELED.equals(scheduledTask.getStatus())) {
                if (System.currentTimeMillis() >= scheduledTask.getScheduledTime().getTime()) {
                    action = MessageFormat.format("<a href=\"#\" onclick=\"javascript:alert(''Not Yet Implemented'')\">Run Now</a>", managerId, taskId, scheduledTask.getJobIdId());
                } else {
                    action = MessageFormat.format("<a href=\"#\" onclick=\"javascript:alert(''Not Yet Implemented'')\">Start</a>", managerId, taskId, scheduledTask.getJobIdId());
                }
            } else if (SCHEDULED.equals(scheduledTask.getStatus())) {
                action = MessageFormat.format("<a href=\"/bash/cancelScheduledTask?managerId={0}&cronId={1}\">Cancel</a>", managerId, scheduledTask.getJobIdId());
            }
            data[counter][0] = taskId;
            data[counter][1] = scheduledTask.getJobIdId();
            data[counter][2] = getSimpleDateString(scheduledTask.getScheduledTime());
            data[counter][3] = scheduledTask.getStatus();
            data[counter][4] = action;
            counter++;
        }
        render(data, columnNames, writer, taskManger.getName(), html);
        return true;
    }

    public static boolean cancelScheduledTask(Long taskId) {

        CronSchedularWorkerManager schedularWorkerManager = CronSchedularWorkerManager.getCronSchedular();
        Map<Long, ScheduledTask> allScheduledTasks = schedularWorkerManager.getAllScheduledTasks();
        Set<Long> taskIdList = allScheduledTasks.keySet();
        for (Long integer : taskIdList) {
            if (taskId.equals(integer)) {
                ScheduledTask scheduledTask = allScheduledTasks.get(integer);
                scheduledTask.cancel();
            }
        }
        return true;
    }

    public static boolean displayPool(PrintWriter writer, String managerId, String poolId, boolean html) {

        try {

            String[] columnNames = {"Id", "Worker Name", "Status", "Action"};

            Map<Integer, WorkerManager> tasks = getEngine().getManagers();

            WorkerManager taskManger = null;
            boolean error = false;
            try {
                taskManger = tasks.get(Integer.parseInt(managerId));
            } catch (Exception e) {
                error = true;
            }

            if (null == taskManger || error) {
                writer.print("Task Id not found " + managerId);
                return false;
            }

            WorkerPool taskPool = null;

            if (taskManger instanceof CronSchedularWorkerManager) {

                CronSchedularWorkerManager cronSchedularWorkerManager = (CronSchedularWorkerManager) taskManger;
                Map<Long, ScheduledTask> allScheduledTasks = cronSchedularWorkerManager.getAllScheduledTasks();
                CronSchedularWorkerManager.TaskSchedular scheduledTask = (CronSchedularWorkerManager.TaskSchedular) allScheduledTasks.get(Long.parseLong(poolId));
                taskPool = scheduledTask.getWorkerPool();
            } else {

                Vector<WorkerPool> threadPools = taskManger.getNumberOfActivePools();
                if (null != threadPools && 0 < threadPools.size()) {
                    for (WorkerPool threadPool : threadPools) {

                        taskPool = threadPool;
                        Integer id = taskPool.getPoolId();
                        if (poolId.equalsIgnoreCase(String.valueOf(id))) {
                            break;
                        } else {
                            taskPool = null;
                        }
                    }
                }
            }
            int counter = 0;
            assert taskPool != null;
            if (null != taskPool) {

                Set<String> keys = taskPool.getworkers().keySet();
                int num = keys.size();
                if (taskPool instanceof ProducerConsumerWorkerPool) {
                    num++;
                }
                Object[][] data = new Object[num][columnNames.length];
                for (String key : keys) {

                    Worker worker = taskPool.getworkers().get(key);

                    String action = "N/A";
                    if (Status.PAUSED.equals(worker.getStatus())) {
                        action = MessageFormat.format("<a href=\"/bash/resumeWorker?managerId={0}&poolId={1}&workerId={2}\">Restart Worker</a>", managerId, taskPool.getPoolId(), worker.getWorkerId());
                    } else if (Status.RUNNING.equals(worker.getStatus())) {
                        action = MessageFormat.format("<a href=\"/bash/pauseWorker?managerId={0}&poolId={1}&workerId={2}\">Pause Worker</a>", managerId, taskPool.getPoolId(), worker.getWorkerId());
                    }

                    if (taskManger instanceof SystemWorkerManager) {
                        action = "N/A";
                    }

                    data[counter][0] = worker.getWorkerId();
                    data[counter][1] = worker.getName();
                    data[counter][2] = worker.getStatus();
                    data[counter][3] = action;
                    counter++;
                }
                if (taskPool instanceof ProducerConsumerWorkerPool) {

                    String action = "N/A";
                    ProducerConsumerWorkerPool pool = (ProducerConsumerWorkerPool) taskPool;
                    DataGatherer worker = pool.getDataGatherer();
                    if (Status.PAUSED.equals(worker.getStatus())) {
                        action = MessageFormat.format("<a href=\"/bash/resumeWorker?managerId={0}&poolId={1}&workerId={2}&type=g\">Restart Gatherer</a>",
                                managerId, taskPool.getPoolId(), worker.getWorkerId());
                    } else if (Status.RUNNING.equals(worker.getStatus())) {
                        action = MessageFormat.format("<a href=\"/bash/pauseWorker?managerId={0}&poolId={1}&workerId={2}&type=g\">Pause Gatherer</a>",
                                managerId, taskPool.getPoolId(), worker.getWorkerId());
                    }
                    data[counter][0] = worker.getWorkerId();
                    data[counter][1] = worker.getName();
                    data[counter][2] = worker.getStatus();
                    data[counter][3] = action;
                }
                render(data, columnNames, writer, poolId.toUpperCase(), html);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return false;
    }

    public static boolean killPool(PrintWriter writer, String managerId, String poolId, boolean html) {

        Map<Integer, WorkerManager> tasks = getEngine().getManagers();
        WorkerManager taskManger = null;
        boolean error = false;
        try {
            taskManger = tasks.get(Integer.parseInt(managerId));
        } catch (Exception e) {
            error = true;
        }

        if (null == taskManger || error) {
            writer.print("Task Id not found " + managerId);
            return false;
        }

        getSystemJobFeeder().submitJob(new SystemJobs.WorkerTask(Long.parseLong(managerId), Long.parseLong(poolId), STOP_POOL));

        return true;
    }

    public static boolean restartPool(PrintWriter writer, String managerId, String poolId, boolean html) {

        Map<Integer, WorkerManager> tasks = getEngine().getManagers();
        WorkerManager taskManger = null;
        boolean error = false;
        try {
            taskManger = tasks.get(Integer.parseInt(managerId));
        } catch (Exception e) {
            error = true;
        }

        if (null == taskManger || error) {
            writer.print("Task Id not found " + managerId);
            return false;
        }

        getSystemJobFeeder().submitJob(new SystemJobs.WorkerTask(Long.parseLong(managerId), Long.parseLong(poolId), RESTART_POOL));

        return true;
    }

    public static boolean pauseWorker(PrintWriter writer, String managerId, String poolId, String workerId, String type, boolean html) {

        try {

            Map<Integer, WorkerManager> tasks = getEngine().getManagers();

            WorkerManager taskManger = null;
            boolean error = false;
            try {
                taskManger = tasks.get(Integer.parseInt(managerId));
            } catch (Exception e) {
                error = true;
            }

            if (null == taskManger || error) {
                writer.print("Task Id not found " + managerId);
                return false;
            }

            Vector<WorkerPool> threadPools = taskManger.getNumberOfActivePools();
            WorkerPool taskPool = null;
            if (null != threadPools && 0 < threadPools.size()) {

                Integer poolIdInt = Integer.parseInt(poolId);
                Long workerIdL = Long.parseLong(workerId);
                for (WorkerPool threadPool : threadPools) {

                    taskPool = threadPool;
                    if (poolIdInt.equals(taskPool.getPoolId())) {
                        if ("g".equalsIgnoreCase(type) && taskPool instanceof ProducerConsumerWorkerPool) {
                            ProducerConsumerWorkerPool pool = (ProducerConsumerWorkerPool) taskPool;
                            pool.getDataGatherer().pause();
                            break;
                        }
                        Map<String, Worker> map = taskPool.getworkers();
                        Set<String> stringSet = map.keySet();
                        for (String s : stringSet) {
                            Worker worker = map.get(s);
                            if (workerIdL.equals(worker.getWorkerId())) {
                                worker.pause();
                                break;
                            }
                        }
                        break;
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return false;
    }

    public static boolean resumeWorker(PrintWriter writer, String managerId, String poolId, String workerId, String type, boolean html) {

        try {

            Map<Integer, WorkerManager> tasks = getEngine().getManagers();

            WorkerManager taskManger = null;
            boolean error = false;
            try {
                taskManger = tasks.get(Integer.parseInt(managerId));
            } catch (Exception e) {
                error = true;
            }

            if (null == taskManger || error) {
                writer.print("Task Id not found " + managerId);
                return false;
            }

            Vector<WorkerPool> threadPools = taskManger.getNumberOfActivePools();
            WorkerPool taskPool = null;
            if (null != threadPools && 0 < threadPools.size()) {

                Integer poolIdInt = Integer.parseInt(poolId);
                Long workerIdL = Long.parseLong(workerId);
                for (WorkerPool threadPool : threadPools) {
                    taskPool = threadPool;
                    if (poolIdInt.equals(taskPool.getPoolId())) {
                        if ("g".equalsIgnoreCase(type) && taskPool instanceof ProducerConsumerWorkerPool) {
                            ProducerConsumerWorkerPool pool = (ProducerConsumerWorkerPool) taskPool;
                            pool.getDataGatherer().resume();
                            break;
                        }
                        Map<String, Worker> map = taskPool.getworkers();
                        Set<String> stringSet = map.keySet();
                        for (String s : stringSet) {
                            Worker worker = map.get(s);
                            if (workerIdL.equals(worker.getWorkerId())) {
                                worker.resume();
                                break;
                            }
                        }
                        break;
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return false;
    }

    public static boolean stopTask(PrintWriter writer, String managerId, String taskId, String workerName, boolean html) {

        try {

            String[] columnNames = {"Id", "Worker Name", "Is Busy"};

            Map<Integer, WorkerManager> tasks = getEngine().getManagers();

            WorkerManager taskManger = null;
            boolean error = false;
            try {
                taskManger = tasks.get(Integer.parseInt(managerId));
            } catch (Exception e) {
                error = true;
            }

            if (null == taskManger || error) {
                writer.print("Task Id not found " + managerId);
                return false;
            }

            Vector<WorkerPool> threadPools = taskManger.getNumberOfActivePools();
            WorkerPool taskPool = null;
            if (null != threadPools && 0 < threadPools.size()) {
                for (WorkerPool threadPool : threadPools) {
                    taskPool = threadPool;
                    if (taskId.equalsIgnoreCase(taskPool.getName())) {
                        taskPool.getworkers().get(workerName).stop();
                        break;
                    }
                }
            }

            int counter = 0;
            assert taskPool != null;
            Set<String> keys = taskPool.getworkers().keySet();
            Object[][] data = new Object[keys.size()][columnNames.length];
            for (String key : keys) {

                Worker worker = taskPool.getworkers().get(key);
                data[counter][0] = worker.getJobId();
                data[counter][1] = worker.getName();
                data[counter][2] = worker.getStatus();
                counter++;
            }
            render(data, columnNames, writer, taskId.toUpperCase(), html);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return false;
    }

    public static boolean handleHelpCommand(String[] args, PrintWriter writer, boolean html) {

        writer.println("Help yet to implemen " + Arrays.toString(args));
        return false;
    }

    public static boolean stopPool() {
        return true;
    }

    public static String getSimpleDateString(Date date) {
        SimpleDateFormat formatter = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss");
        return formatter.format(date);
    }

}
